Java_Concurrency_In_Practise笔记(3) - Composing objects
设计线程安全的类
- 明确类的状态
- 明确类状态之间的限制
- 明确访问类状态时
每个类的所有成员变量组成了这个类的状态,这个类的所有状态组成了相应的状态空间,在状态空间中,如果存在某些无效的状态,那么就要求类有一定的封装来隐藏这些状态空间,否则外部的代码有可能使这个类对象牌处于无效的状态中;另外,如果几个成员变量间有某些不变量,那么对于这些成员变量的操作就必须被原子化,否则可能会破坏这种隐藏的不变量。
例如,如果在某个类中一个自然数以及这个自然数的因子,那么隐含的不变量就是这个自然数必须和这些因子匹配,那么针对这个自然数或者因子的变量的操作就必须是原子化的。类状态变量之间的不变量以及方法的后置条件(比如操作依赖于当前值等)限制了类状态的转移以及有效状态的范围。同样地,方法的前置条件也增加了某些限制。比如,无法从某个空队列中删除元素。在单线程程序中,如果无法满足程序的某些前置条件,那么只要简单地返回错误就可以了,但是在多线程环境下,线程可以等待这些前置条件被满足(其它线程的某些操作使前置条件成立),因此,在多线程编程中提供了wait和notify关键字来实现等待和通知的功能,但是,在使用这两个关键字时,请优先考虑使用已有的框架。比如,阻塞队列,信息量等
实例绑定是最简单地实现线程安全类的方法,具体的做法是使用封装,将一个非线程安全的对象封装到包装对象中,并通过包装对象来控制非线程安全对象的访问,比如HashMap不是个线程安全的集合类,但可以使用平台提供的Collections.synchronizedMap来封装它,从而得到线程安全的hashMap(具体是使用了装饰器模式),只要保证对hashMap对象的访问都是通过封装对象来完成的,那么线程安全就是可以保证的。